/**
 * Copyright 2010 The Regents of the University of California
 *
 *  All Rights Reserved
 */

/**
 *
 * File: arp-cache.c
 * Operations for handling the arp-cache
 */

#include <pthread.h>
#include "stdlib.h"
#include "arp-cache.h"
#include "uthash.h"
#include "vlog.h"


#define THIS_MODULE VLM_arp_cache

arp_cache_record *arp_cache_entry(arp_cache_record ** arp_cache_table, uint32_t nw_addr) {
    arp_cache_record *s;
    HASH_FIND_INT(*arp_cache_table, &nw_addr , s );  /* s: output pointer */
	if(s==NULL)
		VLOG_WARN("Could not find %x", nw_addr);
		
    return s;
}

// We usually dont free the pointer since we are about to add it back. 
// This is because there is no modify in uthash
void delete_arp_cache_entry(arp_cache_record ** arp_cache_table, arp_cache_record *s)
{
    HASH_DEL(*arp_cache_table, s);  /* user: pointer to deletee */
    //free(s);              /* optional; it's up to you! */
}

void add_arp_cache_entry(arp_cache_record ** arp_cache_table, uint32_t nw_addr, uint8_t *dl_addr, uint8_t* pmac, uint32_t pip)
{
    arp_cache_record *s;
    s = malloc(sizeof(arp_cache_record));
    s->nw_addr = nw_addr;
	s->pip = pip;
    memcpy(s->dl_addr, dl_addr,  ETH_ADDR_LEN);
    memcpy(s->pmac, pmac,  ETH_ADDR_LEN);
    HASH_ADD_INT( *arp_cache_table, nw_addr, s );  /* id: name of key field */
	VLOG_DBG("Added entry for ip: %x\t\t%x:%x:%x:%x:%x:%x", s->nw_addr, s->dl_addr[0], s->dl_addr[1], s->dl_addr[2],s->dl_addr[3],s->dl_addr[4], s->dl_addr[5]);
}


void modify_arp_cache_entry(arp_cache_record ** arp_cache_table, arp_cache_record *s, uint8_t *dl_addr, uint8_t* pmac, uint32_t pip )
{
    delete_arp_cache_entry(arp_cache_table, s);
    add_arp_cache_entry(arp_cache_table, s->nw_addr, dl_addr, pmac, pip);
}

int register_in_arp_cache(arp_cache_record ** arp_cache_table, uint32_t nw_addr, uint8_t *dl_addr, uint8_t* pmac, uint32_t pip)
{
    arp_cache_record *s;
    int rc = 0;
	s = arp_cache_entry(arp_cache_table, nw_addr);

	if(s!=NULL)
    {
        if (memcmp(dl_addr, s->dl_addr, ETH_ADDR_LEN) == 0)
        {
            //no need to change
            rc = 0;
        }
        else
        {
			VLOG_WARN("Modifying arp_cache for %x", nw_addr);
            modify_arp_cache_entry(arp_cache_table, s, dl_addr, pmac, pip);
            rc = 1;
        }
    }
    else
    {
		VLOG_WARN("Register %x in arp-cache with amac %x:%x:%x:%x:%x:%x pmac %x:%x:%x:%x:%x:%x", nw_addr, dl_addr[0],dl_addr[1], dl_addr[2], dl_addr[3], dl_addr[4], dl_addr[5], pmac[0],pmac[1],pmac[2],pmac[3],pmac[4],pmac[5]  );
        {
            add_arp_cache_entry(arp_cache_table, nw_addr, dl_addr, pmac, pip);
            rc = 1;
        }
    }
    return rc;
}
